package com.jvyou.app.common.utils.random;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 随机验证码生成工具类
 * <p>
 * 提供多种验证码生成方式，包括：
 * 1. 常规随机验证码
 * 2. 易记型验证码（符合特定规律便于记忆）
 * 3. 数字/字母数字/复杂验证码
 * 4. 自定义字符集验证码
 * </p>
 *
 * @author 橘柚
 * @version 2.0
 * @since 2025-03-31
 */
public class RandomCodeUtil {

    // 数字字符集
    private static final char[] NUMBER_POOL = "0123456789".toCharArray();
    // 字母数字字符集（大写字母+数字）
    private static final char[] LETTER_NUMBER_POOL = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    // 复杂字符集（排除易混淆字符：0,1,I,L,O等）
    private static final char[] COMPLEX_POOL = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ".toCharArray();

    // 常见数字组合（用于生成易记验证码）
    private static final List<String> COMMON_NUMBER_PATTERNS = Arrays.asList(
            "520", "1314", "521", "3344", "168", "888", "666",
            "123", "321", "100", "200", "911", "110", "120"
    );

    // 发音助记部分（用于生成发音易记的验证码）
    private static final String[] PHONETIC_PARTS = {"52", "91", "14", "70", "38", "25"};

    /**
     * 生成6位数字验证码
     *
     * @param easyToRemember 是否生成易记的验证码
     * @return 6位数字验证码
     * @throws IllegalArgumentException 如果参数不合法
     */
    public static String generate6DigitCode(boolean easyToRemember) {
        return easyToRemember ?
                generateEasyToRememberCode(6) :
                generateRandomCode(6, NUMBER_POOL);
    }

    /**
     * 生成指定位数的数字验证码
     *
     * @param length 验证码长度（必须大于0）
     * @param easyToRemember 是否生成易记的验证码
     * @return 数字验证码
     * @throws IllegalArgumentException 如果长度参数不合法
     */
    public static String generateDigitCode(int length, boolean easyToRemember) {
        if (length <= 0) {
            throw new IllegalArgumentException("验证码长度必须大于0");
        }
        return easyToRemember ?
                generateEasyToRememberCode(length) :
                generateRandomCode(length, NUMBER_POOL);
    }

    /**
     * 生成字母数字混合验证码
     *
     * @param length 验证码长度（必须大于0）
     * @return 字母数字混合验证码
     * @throws IllegalArgumentException 如果长度参数不合法
     */
    public static String generateAlphanumericCode(int length) {
        return generateRandomCode(length, LETTER_NUMBER_POOL);
    }

    /**
     * 生成复杂验证码（排除易混淆字符）
     *
     * @param length 验证码长度（必须大于0）
     * @return 复杂验证码
     * @throws IllegalArgumentException 如果长度参数不合法
     */
    public static String generateComplexCode(int length) {
        return generateRandomCode(length, COMPLEX_POOL);
    }

    /**
     * 生成自定义字符集的验证码
     *
     * @param length 验证码长度（必须大于0）
     * @param customPool 自定义字符集（不能为空）
     * @return 自定义验证码
     * @throws IllegalArgumentException 如果参数不合法
     */
    public static String generateCustomCode(int length, String customPool) {
        if (length <= 0) {
            throw new IllegalArgumentException("验证码长度必须大于0");
        }
        if (customPool == null || customPool.isEmpty()) {
            throw new IllegalArgumentException("自定义字符集不能为空");
        }
        return generateRandomCode(length, customPool.toCharArray());
    }

    /**
     * 生成易记的数字验证码
     * <p>
     * 生成的验证码将符合以下特征之一：
     * 1. 常见数字组合拼接（如520131）
     * 2. 两两重复模式（如125812）
     * 3. 发音助记模式（如529114）
     * 4. 有限连续数字（最多3个连续）
     * 5. 有限重复数字（最多3个相同数字）
     * </p>
     *
     * @param length 验证码长度（必须大于0）
     * @return 易记的数字验证码
     * @throws IllegalArgumentException 如果长度参数不合法
     */
    public static String generateEasyToRememberCode(int length) {
        if (length <= 0) {
            throw new IllegalArgumentException("验证码长度必须大于0");
        }

        Random random = ThreadLocalRandom.current();
        int pattern = random.nextInt(5); // 随机选择一种易记模式

        switch (pattern) {
            case 0: // 常见数字组合拼接
                return generateCommonPatternCode(length);

            case 1: // 两两重复模式
                return generatePairRepeatCode(length);

            case 2: // 发音助记模式
                return generatePhoneticCode(length);

            case 3: // 有限连续数字
                return generateLimitedSequenceCode(length, 3);

            case 4: // 有限重复数字
                return generateLimitedRepeatCode(length, 3);

            default:
                return generateRandomCode(length, NUMBER_POOL);
        }
    }

    /**
     * 基础随机生成方法
     *
     * @param length 验证码长度
     * @param pool 字符池
     * @return 随机验证码
     */
    private static String generateRandomCode(int length, char[] pool) {
        Random random = ThreadLocalRandom.current();
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(pool[random.nextInt(pool.length)]);
        }
        return sb.toString();
    }

    /**
     * 生成常见数字组合验证码
     */
    private static String generateCommonPatternCode(int length) {
        Random random = ThreadLocalRandom.current();
        StringBuilder sb = new StringBuilder(length);

        while (sb.length() < length) {
            String pattern = COMMON_NUMBER_PATTERNS.get(random.nextInt(COMMON_NUMBER_PATTERNS.size()));
            sb.append(pattern);
        }

        return sb.substring(0, length);
    }

    /**
     * 生成两两重复验证码
     */
    private static String generatePairRepeatCode(int length) {
        Random random = ThreadLocalRandom.current();
        int halfLength = (length + 1) / 2; // 向上取整
        StringBuilder firstHalf = new StringBuilder(halfLength);

        for (int i = 0; i < halfLength; i++) {
            firstHalf.append(NUMBER_POOL[random.nextInt(NUMBER_POOL.length)]);
        }

        String code = firstHalf.toString();
        return code + code.substring(0, length - halfLength);
    }

    /**
     * 生成发音助记验证码
     */
    private static String generatePhoneticCode(int length) {
        Random random = ThreadLocalRandom.current();
        StringBuilder sb = new StringBuilder(length);

        while (sb.length() < length) {
            String part = PHONETIC_PARTS[random.nextInt(PHONETIC_PARTS.length)];
            sb.append(part);
        }

        return sb.substring(0, length);
    }

    /**
     * 生成有限连续数字验证码
     */
    private static String generateLimitedSequenceCode(int length, int maxSequence) {
        Random random = ThreadLocalRandom.current();
        StringBuilder sb = new StringBuilder(length);

        int lastDigit = -1;
        int sequenceLength = 0;

        for (int i = 0; i < length; i++) {
            int digit;
            do {
                digit = random.nextInt(10);
                // 检查是否超过最大连续长度
                if (digit == lastDigit) {
                    sequenceLength++;
                } else {
                    sequenceLength = 1;
                }
            } while (sequenceLength > maxSequence);

            sb.append(digit);
            lastDigit = digit;
        }
        return sb.toString();
    }

    /**
     * 生成有限重复数字验证码
     */
    private static String generateLimitedRepeatCode(int length, int maxRepeat) {
        Random random = ThreadLocalRandom.current();
        StringBuilder sb = new StringBuilder(length);
        int[] counts = new int[10]; // 记录每个数字出现的次数

        for (int i = 0; i < length; i++) {
            int digit;
            do {
                digit = random.nextInt(10);
            } while (counts[digit] >= maxRepeat);

            sb.append(digit);
            counts[digit]++;
        }
        return sb.toString();
    }
}